import java.io.*;
import java.net.*;
import java.util.*;import java.util.regex.*;

public class Ftp
	extends FileService
{
	Socket skt = null;	ObjectInputStream oin = null;	ObjectOutputStream oout = null;	boolean quit = false;
	boolean mode = FileService.BINARY;
	FileService fs = new FileService();
	
	public static void main(String args[])
	{
		if (args.length < 1)
		{
			System.out.println("Usage java Ftp host [port]");
			System.exit(1);
		}
		int port = 21214;
		if (args.length > 1)
			port = Integer.parseInt(args[1]);
		Ftp ftp = new Ftp(args[0], port);
	}
	
	public Ftp(String host, int port)
	{
		try 
		{
			skt = new Socket(host, port);			oin = new ObjectInputStream(skt.getInputStream());			oout = new ObjectOutputStream(skt.getOutputStream());
			while (!quit)
			{				Command cmd = readCommand();
				executeCommand(cmd);
			}			}		catch (Exception ex)
		{
			ex.printStackTrace();		}
		finally		{			try			{				skt.close();
			}
			catch (Exception ex)
			{
				ex.printStackTrace();
			}		}
	}		public Command readCommand()	{			Command cmd = new Command();
		boolean parseSuccessful = false;
				while (!parseSuccessful)
		{			String cmdstr = ScreenIO.promptForString("FTP> ");
			String[] args = Pattern.compile(" ").split(cmdstr, 2);					for (int i = 0; i < Command.COMMAND.length; ++i)			{
				if (args[0].equalsIgnoreCase(Command.COMMAND[i]))				{
					cmd.commandID = i;
					if (args.length > 1)						cmd.commandArg = args[1];
					parseSuccessful = true;					break;
				}		
			}		}
		
		return cmd;
	}
	
	public void executeCommand(Command cmd)
	{	switch (cmd.commandID)
		{
			case Command.ASCII:
				mode = FileService.ASCII;
				break;
			case Command.BINARY:
				mode = FileService.BINARY;
				break;
			case Command.QUIT:
				quit = true;
				break;
			case Command.LCD:
				lcd(cmd.commandArg);
				return;
			case Command.LLS:
				lls();
				return;
			case Command.LMKDIR:
				lmkdir(cmd.commandArg);
				return;
			case Command.LPWD:
				lpwd();
				return;
		}			
			
		if (cmd.isRemote())
			exeRemoteCommand(cmd);							}
	
	public void exeRemoteCommand(Command cmd)
	{
		try 		{			oout.writeObject(cmd);	
			oout.flush();			switch (cmd.commandID)			{				case Command.GET:					get(cmd.commandArg);					break;				case Command.MGET:					mget(cmd.commandArg);					break;
				case Command.PUT:
					put(cmd.commandArg);
					break;
				case Command.MPUT:
					mput(cmd.commandArg);
					break;				default:
					String result = oin.readObject().toString();					System.out.println(result);
			}		}		catch (Exception ex)		{
			quit = true;			ex.printStackTrace();		}
	}
	
	public void get(String args)
	{
		try
		{
			FileHeader header = (FileHeader)oin.readObject();
			
			if (header.isFile && header.canRead)
			{
				oout.writeBoolean(true);
				oout.flush();
				if (mode)
					fs.receiveBinaryFile(header, skt);
				else
					fs.receiveAsciiFile(header, skt);
			}
		} 
		catch (Exception ex)
		{
			quit = true;
			ex.printStackTrace();
		}
	}
	
	public void mget(String args)
	{
		try
		{
			Vector headers = (Vector)oin.readObject();
			Iterator it = headers.iterator();
			
			while (it.hasNext())
			{
				FileHeader header = (FileHeader)it.next();
				char c = ScreenIO.promptForChar("Download file '" + 
									   header.name + 
									   "' ('y' or 'n')?");
				if (c == 'y' || c == 'Y')
				{
					Command cmd = new Command();
					cmd.commandID = Command.GET;
					cmd.commandArg = header.name;
					executeCommand(cmd);
				}
			}
		}
		catch (Exception ex)
		{
			quit = true;
			ex.printStackTrace();
		}
	}
	
	public void put(String args)
	{
		try
		{
			File file = fs.getFileObject(args);	
			FileHeader header = fs.getFileHeader(file);
			oout.writeObject(header);
			oout.flush();
			
			if (file.canRead() && file.isFile())
			{
				if (oin.readBoolean())
				{
					if (mode)
						fs.sendBinaryFile(file, skt);
					else
						fs.sendAsciiFile(file, skt);
				}
			}
		}
		catch (Exception ex)
		{
			quit = true;
			ex.printStackTrace();
		}
	}
	
	public void mput(String args)
	{		
		File[] files = fs.matches(args);
		for (int i = 0; i < files.length; i++)
		{
			if (files[i].isFile() && files[i].canRead())
			{
				char c = ScreenIO.promptForChar("upload file '" + 
								   files[i].getName() + 
								   "' ('y' or 'n')?");
				if (c == 'y' || c == 'Y')
				{
					Command cmd = new Command();
					cmd.commandID = Command.PUT;
					cmd.commandArg = files[i].getName();
					executeCommand(cmd);
				}	
			}
		}		
	}
	
	public void lls()
	{
		String[] list = fs.ls();
		
		for (int i = 0; i < list.length; ++i)
			System.out.println(list[i]);
		
		System.out.println();
	}
	
	public void lcd(String args)
	{
		fs.cd(args);
	}
	
	public void lpwd()
	{
		System.out.println(fs.pwd());	
	}
	
	public void lmkdir(String args)
	{
		fs.mkdir(args);	
	}
}
